package com.zx.service.Impl;/**
 * Author:JasonZ
 * Data:2023/4/19
 */

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.zx.common.TableId;
import com.zx.constant.GoodsConstant;
import com.zx.dao.ECommerceGoodsDao;
import com.zx.entity.EcommerceGoods;
import com.zx.service.IGoodsService;
import com.zx.vo.DeductGoodsInventory;
import com.zx.vo.GoodsInfo;
import com.zx.vo.PageSimpleGoodsInfo;
import com.zx.vo.SimpleGoodsInfo;
import javafx.scene.control.Tab;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @program: ecommerce-parent
 * @description:
 * @author: JasonZ
 * @create: 2023-04-19 14:40
 **/
@Service
@Slf4j
public class IGoodsServiceImpl implements IGoodsService {
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private ECommerceGoodsDao goodsDao;

    //根据商品信息查询(多个商品ID)
    @Override
    public List<GoodsInfo> getGoodsInfo(TableId tableId) {
        //查询出所有ID对应的商品信息
        List<EcommerceGoods> ecommerceGoodsList = goodsDao.findAllById
                (tableId.getIds().stream().map(TableId.Id::getId).collect(Collectors.toList()));
        //转换成传输类型
        List<GoodsInfo> goodsInfoList = ecommerceGoodsList.stream().map(EcommerceGoods::toGoodsInfo).collect(Collectors.toList());
        return goodsInfoList;
    }

    //查询简单商品信息 封面
    @Override
    public List<SimpleGoodsInfo> getSimpleGoodsInfoByTableId(TableId tableId) {
        //1.获取到所有商品id
        List<Object> ids = tableId.getIds().stream().map(id -> id.getId().toString()).collect(Collectors.toList());
        //查看redis缓存当中是否有相对应的商品数据
        List<Object> cacheSimpleGoods = stringRedisTemplate.opsForHash().multiGet(GoodsConstant.REDIS_GOODS_INFO_KEY, ids)
                /*过滤掉空的*/
                .stream()
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(cacheSimpleGoods)) {
            //集合不为空 继续判断
            if (cacheSimpleGoods.size() == ids.size()) {
                //对应的id数据都在缓存当中 说明加载了全部的商品数据
                return parseSimpleGoodsInfoFromCache(cacheSimpleGoods);
            } else {
                //对应的id数据不是全都在缓存当中 需要取差集
                //先获取simpleGoodsInfo类的集合
                List<SimpleGoodsInfo> goodsInfos = parseSimpleGoodsInfoFromCache(cacheSimpleGoods);
                //取到id的差集
                Collection<Object> subtract = CollectionUtil.subtract(
                        ids,
                        goodsInfos.stream().map(SimpleGoodsInfo::getId).collect(Collectors.toList())
                );
                //使用差集的id查询DB 并且存入redis
                //把差集转换成List集合
                List<Long> subIds = subtract.stream().
                        map(s -> Long.valueOf(s.toString())).collect(Collectors.toList());
                //查询id对应的集合
                List<EcommerceGoods> ecommerceGoodsList = goodsDao.findAllById(subIds);
                List<SimpleGoodsInfo> subSimpleGoods = ecommerceGoodsList.stream().map(EcommerceGoods::toSimple).collect(Collectors.toList());
                //把差集的缓存数据存入到redis当中
                saveNewGoodsInfoToRedis(subSimpleGoods);
                //合并数据并返回
                return CollectionUtil.union(
                        goodsInfos,
                        subSimpleGoods
                ).stream().collect(Collectors.toList());
            }
        }
        else {
            //否则redis未存入数据 查数据库并且保存到redis当中
            List<EcommerceGoods> ecommerceGoods = goodsDao.findAllById(tableId.getIds().stream()
                    .map(TableId.Id::getId).collect(Collectors.toList()));
            //把商品数据转换成商品建议数据
            List<SimpleGoodsInfo> simpleGoodsInfos = ecommerceGoods.stream()
                    .map(EcommerceGoods::toSimple).collect(Collectors.toList());
            //保存到redis当中
            saveNewGoodsInfoToRedis(simpleGoodsInfos);
            return simpleGoodsInfos;
        }
    }

    //分页查询商品信息
    @Override
    public PageSimpleGoodsInfo getSimpleGoodsInfoByPage(int page) {
        if (page <= 1) {
            page = 1;
        }
        Pageable pageable = PageRequest.of(
                page - 1, 10, Sort.by("id").descending()
        );
        Page<EcommerceGoods> pager = goodsDao.findAll(pageable);
        Boolean hasMore = pager.getTotalPages() > page;
        return new PageSimpleGoodsInfo(
                pager.getContent().stream().map(EcommerceGoods::toSimple).collect(Collectors.toList()),
                hasMore
        );
    }

    //商品减存  inventory库存
    //[{gid: 1,count:50},{gid:2,count:100}]
    // [{商品id:1,数量50}，{商品id:2,数量50}，{商品id:3,数量50}，{商品id:4,数量50}]
    @Override
    public Boolean deductGoodsInventory(List<DeductGoodsInventory> deductGoodsInventories) {
        //1.根据需要减存的商品id 查询出对应的商品对象
        List<Long> ids = deductGoodsInventories.stream().map(DeductGoodsInventory::getId).collect(Collectors.toList());
        List<EcommerceGoods> currentGoodsList = goodsDao.findAllById(ids);
        //现在需要把每一个对应的商品数量进行减存 也就是要双重循环 这里推荐转换成map集合
        // 转MAP  goodsList  deductGoodsInventories
        // MAP O(1)
        //Function.identity() 指的是对象本身 把参照的集合id转换成map
        Map<Long, DeductGoodsInventory> inventoryMap = deductGoodsInventories.stream().collect(Collectors.toMap(
                DeductGoodsInventory::getId,
                Function.identity()
        ));

        currentGoodsList.forEach(g -> {
            //获取当前的商品信息
            DeductGoodsInventory deductGoodsInventory = inventoryMap.get(g.getId());
            //现有的数量
            Long currentCount = g.getInventory();
            //要扣减的库存量
            Long needDeductInventory = deductGoodsInventory.getCount();
            if (needDeductInventory > currentCount) {
                throw new RuntimeException("商品库存不足！");
            }
            g.setInventory(currentCount - needDeductInventory);
        });
        //满足条件 重新持久化修改之后的结果
        goodsDao.saveAll(currentGoodsList);
        return true;
    }

    /*把object类的转成SimpleGoodsInfo类的集合*/
    private List<SimpleGoodsInfo> parseSimpleGoodsInfoFromCache(List<Object> cacheSimpleGoods) {
        return cacheSimpleGoods.stream().map
                        (s -> JSON.parseObject(s.toString(), SimpleGoodsInfo.class))
                .collect(Collectors.toList());
    }

    /*根据商品封面信息保存到redis当中*/
    private void saveNewGoodsInfoToRedis(List<SimpleGoodsInfo> simpleGoodsInfos) {
        Map<String, String> id2JsonObject = new HashMap<>();
        simpleGoodsInfos.forEach(g -> id2JsonObject.put(g.getId().toString(), JSON.toJSONString(g)));
        stringRedisTemplate.opsForHash().putAll(GoodsConstant.REDIS_GOODS_INFO_KEY,
                id2JsonObject
        );
    }
}
